pub fn learn_sharedstate() {
  //_learn_mutex0();
  _learn_mutex2();
}

// 互斥器一次只允许一个线程访问数据
// 互斥器通过锁系统包含其数据
// 在使用数据之前尝试获取锁
// 处理完被互斥器锁保护的数据之后,必须解锁.这样其他线程才能够获取锁

// Mutext<T>的API
use std::sync::Mutex;

fn _learn_mutex0() {
  let m = Mutex::new(5);
  {
    // 阻塞当前线程,直到拿到锁为止
    // 如果另一个线程拥有锁,并且那个线程panic了,则lock调用会失败.这种情况下,其他线程都无法获取锁.
    // 拿到锁后,返回值就可以视为一个内部数据的可变引用.
    let mut num = m.lock().unwrap();
    *num = 6;
  }
  println!("m={:?}", m);
} // 离开作用域后,锁自动释放(若要提前释放以使其他线程可用,需要手动释放)

// 在线程间共享Mutex<T>
use std::thread;

/*
fn _learn_mutex1(){
    // 创建counter变量来存放内含i32的Mutex<T>
    let counter = Mutex::new(0);
    let mut handles = vec![];
    for _ in 0..10 {
        // counter已经被移动过了,循环的下一次迭代不能再移动了
        let handle = thread::spawn(move||{
            let mut num=counter.lock().unwrap();
            *num+=1;
        });
        handles.push(handle);
    }
    for h in handles {
        h.join().unwrap();
    }
    // counter的所有权已经被移动走了
    //println!("Result:{}", *counter.lock().unwrap());
}
*/

// 多线程和多所有权
// Rc不适用多线程环境
// 原子引用计数Arc<T>
use std::sync::Arc;

fn _learn_mutex2() {
  let counter = Arc::new(Mutex::new(0));
  let mut handles = vec![];
  for _ in 0..10 {
    let counter = Arc::clone(&counter);
    let handle = thread::spawn(move || {
      let mut num = counter.lock().unwrap();
      *num += 1;
    });
    handles.push(handle);
  }
  for h in handles {
    h.join().unwrap();
  }
  println!("Result:{}", *counter.lock().unwrap());
}

// RefCell<T>/Rc<T>与Mutex<T>/Arc<T>的相似性
// counter是不可变的,但可以获取其内部值的可变引用;即Mutex<T>提供了内部可变性,
// 就像Cell系列那样.
// 需要注意,rust不能避免适用Mutex<T>的全部逻辑错误.同样,Mutex<T>也有造成
// 死锁的风险.

// 使用Sync和Send trait的可扩展并发

// 通过Send允许在线程间转移所有权
// Send标记trait表明实现了Send的类型值的所有权可以在线程间传送.几乎所有的Rust
// 类型都是Send的.不过有一些例外,包括Rc<T>,这是不能Send的.如果克隆了Rc<T>的值并
// 尝试将克隆的所有权转移到另一个线程,这两个线程都可能同时更新引用计数.因此,Rc<T>
// 被实现为用于单线程场景.
// 几乎所有基本类型都是Send的,除了裸指针(raw pointer)

// Sync允许多线程访问
// Sync标记trait表明实现了Sync的类型可以安全的在多个线程中拥有其值的引用.
// 换句话说,对于任意类型T,如果&T(T的不可变引用)是Send的话, T就是Sync的,
// 这意味着其引用就可以安全的发送到另一个线程.类似于Send的情况,基本类型是
// Sync的,完全由Sync的类型组成的类型也是Sync的.

// 智能指针Rc<T>不是Sync的,与它不是Send的原因相同.RefCell<T>和Cell<T>系列
// 类型也不是Sync的. RefCell<T>在运行时所进行的借用检查也不是线程安全的.
// Mutex<T>是Sync的

// 手动实现Send和Sync是不安全的
